package services

import (
	"fmt"
	"github.com/gomodule/redigo/redis"
	"log"
	"lottery/comm"
	"lottery/dao"
	"lottery/datasource"
	"lottery/models"
)

type UserService interface {
	GetAll(page, size int) []models.LtUser
	CountAll() int64
	//Search(country string) []models.LtUser
	Get(id int) (*models.LtUser, bool)
	//Delete(id int) error
	Update(user *models.LtUser, columns []string) error
	Create(user *models.LtUser) error
}

type userService struct {
	dao *dao.UserDao
}

func NewUserService() UserService {
	return &userService{
		dao: dao.NewUserDao(datasource.InstanceDB()),
	}
}

func (s *userService) Get(id int) (*models.LtUser, bool) {
	// 读取缓存
	data := s.getByCache(id)
	if data == nil || data.Id <= 0 {
		data, _ = s.dao.Get(id)
		// 如果数据库中也是 空值, 或不合法
		if data == nil || data.Id <= 0 {
			data = &models.LtUser{Id: id}
		}
		// 构造空值添加进缓存，避免每次都访问数据库
		// 如果真的插入了 这个 id的用户数据的话，Create方法，会进行删除对应的缓存，
		// 这里会重新设置，新的正确用户数据的缓存。
		s.setByCache(data)
	}
	if data.Username == "" {
		return data, false
	} else {
		return data, true
	}
}

func (s *userService) GetAll(page, size int) []models.LtUser {
	datalist, _ := s.dao.GetAll(page, size)
	return datalist
}

//
func (s *userService) CountAll() int64 {
	return s.dao.CountAll()
}

////func (s *userService) Search(country string) []models.LtUser {
////	return s.dao.Search(country)
////}

////func (s *userService) Delete(id int) error {
////	return s.dao.Delete(id)
////}

func (s *userService) Update(data *models.LtUser, columns []string) error {
	s.updateByCache(data, columns)
	// 然后再更新数据
	return s.dao.Update(data, columns)
}

func (s *userService) Create(data *models.LtUser) error {
	err := s.dao.Create(data)
	// 结果更新到对应的数据中
	if err == nil {
		s.updateByCache(data, nil)
	}
	return err
}

func (s *userService) getByCache(id int) *models.LtUser {
	// 构造key
	key := fmt.Sprintf("info_user_%d", id)
	rds := datasource.InstanceCache()
	// 获取 用户所有信息: StringMap 查看官方文档，得到的是字符类型map
	dataMap, err := redis.StringMap(rds.Do("HGETALL", key))
	if err != nil {
		log.Println("user_service.getByCache HGETALL key=", key, ", error=", err)
		return nil
	}
	dataId := comm.GetInt64FromStringMap(dataMap, "Id", 0)
	if dataId <= 0 {
		return nil
	}
	// 进行转换存入models.LtUser 模型中
	data := &models.LtUser{
		Id:         int(dataId),
		Username:   comm.GetStringFromStringMap(dataMap, "Username", ""),
		BlackTime:  int(comm.GetInt64FromStringMap(dataMap, "Blacktime", 0)),
		RealName:   comm.GetStringFromStringMap(dataMap, "Realname", ""),
		Mobile:     comm.GetStringFromStringMap(dataMap, "Mobile", ""),
		Address:    comm.GetStringFromStringMap(dataMap, "Address", ""),
		SysCreated: int(comm.GetInt64FromStringMap(dataMap, "SysCreated", 0)),
		SysUpdated: int(comm.GetInt64FromStringMap(dataMap, "SysUpdated", 0)),
	}
	return data
}

func (s *userService) setByCache(data *models.LtUser) {
	if data == nil || data.Id <= 0 {
		return
	}
	id := data.Id
	key := fmt.Sprintf("info_user_%d", id)
	rds := datasource.InstanceCache()
	// 封装的方便构造参数的
	params := redis.Args{}
	params = params.Add(key)
	params = params.Add("Id", id)
	if data.Username != "" {
		// 参数传递
		params = params.AddFlat(data)
	}
	_, err := rds.Do("HMSET", params...)
	if err != nil {
		log.Println("user_service.setByCache HMSET params=", params, ", error=", err)
	}
}

func (s *userService) updateByCache(data *models.LtUser, columns []string) {
	if data == nil && data.Id <= 0 {
		return
	}
	// 这里不做细节的更新， 比方说根据传入的 columns 进行更新。 直接删除掉整个key
	// 这样是方便了， 因为对于每个字段，可能需要单独的进行验证，所以这里简化起来，直接全删
	key := fmt.Sprintf("info_user_%d", data.Id)
	rds := datasource.InstanceCache()
	// 删除redis中的缓存
	rds.Do("DEL", key)
}
